package org.commons;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.sql.Timestamp;
import java.util.Iterator;
import java.util.List;

import org.commons.libraries.VectorClock;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

import app.resources.Context;
import app.resources.Resource;



public class XmlLogger {

	public static void createXml(String storagePath) {
		File list = new File(storagePath+File.separator+"recovery.xml");
		if (!list.exists()) {
			Element root = new Element("recovery");
			Document document = new Document(root);	
			root.addContent(new Element("keys"));
			root.addContent(new Element("temporaryKeys"));
			XMLOutputter out = new XMLOutputter();
			out.setFormat(Format.getPrettyFormat());
			try {
				out.output(document, new FileOutputStream(storagePath+File.separator+"recovery.xml"));
			} catch (FileNotFoundException ex) {
			} catch (IOException ex) {
			}
		}
	}
	
	public static int getIP(String storagePath) {
		int toReturn = 0;
		Document document = null;
		SAXBuilder sb = new SAXBuilder();
		try {
			document = sb.build(new File(storagePath+File.separator+"recovery.xml"));
		} catch (JDOMException e) {
		} catch (IOException e) {
		}
		Element root = document.getRootElement();
		String port = root.getChild("address").getText();
		if (!port.equals(""))
			toReturn = Integer.parseInt(port);
		return toReturn;
	}
	
	public static void setIP(String storagePath, String ip) {
		Document document = null;
		SAXBuilder sb = new SAXBuilder();
		try {
			document = sb.build(new File(storagePath+File.separator+"recovery.xml"));
		} catch (JDOMException e) {
		} catch (IOException e) {
		}
		Element root = document.getRootElement();
		root.addContent(new Element("address").setText(ip+""));
		XMLOutputter out = new XMLOutputter();
		out.setFormat(Format.getPrettyFormat());
		try {
			out.output(document, new FileOutputStream(storagePath+File.separator+"recovery.xml"));
		} catch (FileNotFoundException ex) {
		} catch (IOException ex) {
		}
	}

	public static XMLResource[] getXmlResources (String storagePath, String kind) {
		Document document = null;
		SAXBuilder sb = new SAXBuilder();
		try {
			document = sb.build(new File(storagePath+File.separator+"recovery.xml"));
		} catch (JDOMException e) {
			return null;
		} catch (IOException e) {
			return null;
		}
		Element root = document.getRootElement();
		Element resources = root.getChild(kind);

		@SuppressWarnings("unchecked")
		List<Element> resourcesList = resources.getChildren("resource");
		XMLResource[] resRetrieved = new XMLResource[resourcesList.size()]; 
		Iterator<Element> resourcesIterator = resourcesList.iterator();
		int key;
		String owner;
		String fileName;
		Timestamp lastModified;
		String host;
		int port;
		int responsibleVirtualNode;
		Context c;
		for (int i=0; resourcesIterator.hasNext(); i++) {
			Element resourceItem = resourcesIterator.next();
			key = Integer.parseInt(resourceItem.getAttributeValue("key"));
			fileName =resourceItem.getAttributeValue("fileName");
			owner = resourceItem.getAttributeValue("owner");
			responsibleVirtualNode = Integer.parseInt(resourceItem.getAttributeValue("responsibleVN"));
			lastModified = Timestamp.valueOf(resourceItem.getAttributeValue("lastModified"));
			InetSocketAddress isa = null;
			if (kind.equals("temporaryKeys")) {
				host = resourceItem.getAttributeValue("host");
				port = Integer.parseInt(resourceItem.getAttributeValue("port"));
				try {
					isa = new InetSocketAddress(InetAddress.getByName(host.substring(1)), port);
				} catch (UnknownHostException e) {
				}
				
			}
			FileInputStream fis;
			byte[] object = null;
			try {
				if (kind.equals("keys")) 
					fis = new FileInputStream(storagePath+File.separator+owner+File.separator+fileName);
				else
					fis = new FileInputStream(storagePath+File.separator+owner+File.separator+"temp"+File.separator+fileName);
				object = new byte[fis.available()];
				for (int k=0; k < object.length; k++) {
					object[k] = (byte) fis.read();
				}
			} catch (FileNotFoundException e) {
				System.out.println("File not found");
				return null;
			} catch (IOException e) {
				e.printStackTrace();
				return null;
			}
			c = new Context(fileName, owner, object);
			c.setLastModified(lastModified);

			resRetrieved[i] = new XMLResource(new Resource(key, c, owner), isa, responsibleVirtualNode);
			Element vectorClocks = resourceItem.getChild("vectorClocks");
			@SuppressWarnings("unchecked")
			Iterator<Element> vectorIterator = vectorClocks.getChildren("node").iterator();
			VectorClock vc = new VectorClock();
			while(vectorIterator.hasNext()) {
				Element vector = vectorIterator.next();
				vc.put(vector.getAttributeValue("nName"), Integer.parseInt(vector.getText()));
			}
			resRetrieved[i].getResource().setVectorClock(vc);
		}
		return resRetrieved;
	}

	public static void updateXml (String storagePath, String kind, int resourceKey, String filename, String owner, Timestamp lastModified, VectorClock clocks, InetSocketAddress isa, int responsible) {
		Document document = null;
		SAXBuilder sb = new SAXBuilder();
		try {
			document = sb.build(new File(storagePath+File.separator+"recovery.xml"));
		} catch (JDOMException e) {
		} catch (IOException e) {
		}
		Element root = document.getRootElement();
		Element resources = root.getChild(kind);
		@SuppressWarnings("unchecked")
		List<Element> resourcesList = resources.getChildren("resource");
		Iterator<Element> resourcesIterator = resourcesList.iterator();
		boolean updated = false;
		while (resourcesIterator.hasNext()) {
			Element resourceItem = resourcesIterator.next();
			if (Integer.parseInt(resourceItem.getAttributeValue("key")) == resourceKey) {
				resourceItem.setAttribute("fileName", filename);
				resourceItem.setAttribute("owner", owner);
				resourceItem.setAttribute("responsibleVN", responsible+"");
				resourceItem.setAttribute("lastModified", lastModified.toString());
				if (kind.equals("temporaryKeys")) {
					resourceItem.setAttribute("host", isa.getAddress().toString());
					resourceItem.setAttribute("port", isa.getPort()+"");
				}
				Element vClock = resourceItem.getChild("vectorClocks");
				vClock.removeChildren("node");
				Iterator<String> i = clocks.keySet().iterator();
				String temp = "";
				int value = 0;
				while (i.hasNext()) {
					temp = i.next();
					value = clocks.get(temp);
					vClock.addContent(new Element("node").setAttribute("nName", temp).setText(value+""));
				}
				updated = true;
			}
		}
		if (!updated) {
			Element newResource = new Element("resource");
			newResource.setAttribute("key", resourceKey+"");
			newResource.setAttribute("fileName", filename);
			newResource.setAttribute("owner", owner);
			newResource.setAttribute("responsibleVN", responsible+"");
			newResource.setAttribute("lastModified", lastModified.toString());
			if (kind.equals("temporaryKeys")) {
				newResource.setAttribute("host", isa.getAddress().toString());
				newResource.setAttribute("port", isa.getPort()+"");
			}
			Element vectorClocks = new Element("vectorClocks");
			Iterator<String> i = clocks.keySet().iterator();
			String temp = "";
			int value = 0;
			while (i.hasNext()) {
				temp = i.next();
				value = clocks.get(temp);
				vectorClocks.addContent(new Element("node").setAttribute("nName", temp).setText(value+""));
			}
			newResource.addContent(vectorClocks);
			resources.addContent(newResource);
		}
		XMLOutputter out = new XMLOutputter();
		out.setFormat(Format.getPrettyFormat());
		try {
			out.output(document, new FileOutputStream(storagePath+File.separator+"recovery.xml"));
		} catch (FileNotFoundException ex) {
		} catch (IOException ex) {
		}
	}

	public static void removeKey (String storagePath, String kind, int resourceKey) {
		Document document = null;
		SAXBuilder sb = new SAXBuilder();
		try {
			document = sb.build(new File(storagePath+File.separator+"recovery.xml"));
		} catch (JDOMException e) {
		} catch (IOException e) {
		}
		Element root = document.getRootElement();
		Element oldResources = root.getChild(kind);
		Element newResources = new Element(kind);

		@SuppressWarnings("unchecked")
		List<Element> resourcesList = oldResources.getChildren("resource");
		Iterator<Element> resourcesIterator = resourcesList.iterator();
		while (resourcesIterator.hasNext()) {
			Element resourceItem = resourcesIterator.next();
			if (Integer.parseInt(resourceItem.getAttributeValue("key")) != resourceKey) {
				newResources.addContent((Element)resourceItem.clone());
			}
		}
		root.removeChild(kind);
		root.addContent(newResources);
		XMLOutputter out = new XMLOutputter();
		out.setFormat(Format.getPrettyFormat());
		try {
			out.output(document, new FileOutputStream(storagePath+File.separator+"recovery.xml"));
		} catch (FileNotFoundException ex) {
		} catch (IOException ex) {
		}
	}
	
	public static String getConfig(String storagePath, String element) {
		Document document = null;
		SAXBuilder sb = new SAXBuilder();
		try {
			document = sb.build(new File(storagePath+File.separator+"config"+File.separator+"config.xml"));
		} catch (JDOMException e) {
		} catch (IOException e) {
		}
		return document.getRootElement().getChild(element).getText();
	}
}
